package scoutobahn.xml;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
/**
 * Class that loads all nodes for OsmRelation.
 * @author mark
 *
 */
public class OsmRelationNodeCollector {
    private final OsmRelation startRelation;
    private final OsmItemProvider provider;
    /**
     * Creates a new OsmRelationNodeCollector for the given OsmRelation.
     * with the given OsmItemProvider to resolve lazy OsmItems
     * @param osmRelation The OsmRelation who's nodes will be collected
     * @param osmProvider The OsmItemProvider to resolve lazy OsmItems
     */
    public OsmRelationNodeCollector(final OsmRelation osmRelation,
            final OsmItemProvider osmProvider) {
        this.startRelation = osmRelation;
        this.provider = osmProvider;
    }
    /**
     * Collect's all nodes of the OsmRelation.
     * @return The collection of OsmNode
     */
    public Collection<OsmNode> collectNodes() {
        return this.collectNodes(
                this.startRelation,
                new LinkedList<OsmNode>(),
                        new HashSet<Long>());
    }

    private Collection<OsmNode> collectNodes(final OsmRelation relation,
            final Collection<OsmNode> nodes,
            final Set<Long> marked) {
        for (OsmRelationMember member : relation.getMember()) {
            long memberId = member.getReferencedItem().getId();
            if (member.getType().equals(OsmXmlTypes.Node)
                    && this.provider.hasItem(memberId, OsmXmlTypes.Node)) {
                nodes.add((OsmNode) provider
                        .getItemById(memberId, OsmXmlTypes.Node));
            } else if (member.getType().equals(OsmXmlTypes.Way)
                    && this.provider.hasItem(memberId, OsmXmlTypes.Way)) {
               this.collectFromWay((OsmWay) this.provider
                       .getItemById(memberId, OsmXmlTypes.Way), nodes);
            } else if (member.getType().equals(OsmXmlTypes.Relation)
                    && this.provider.hasItem(memberId, OsmXmlTypes.Relation)) {
               if (!marked.contains(memberId)) {
                   marked.add(memberId);
                   this.collectNodes(
                           (OsmRelation) this.provider.getItemById(memberId,
                                   OsmXmlTypes.Relation), nodes, marked);
               }
            }
        }
        return nodes;
    }
    /**
     * Collects all OsmNodes of the given way.
     * @param way The OsmWay who's OsmNodes are collected
     * @param nodes This list of nodes where the nodes will be added
     * @return The nodes list
     */
    private Collection<OsmNode> collectFromWay(final OsmWay way,
            final Collection<OsmNode> nodes) {
        for (OsmItem item : way.getNodes()) {
            nodes.add((OsmNode) this.provider.getItemById(
                    item.getId(), OsmXmlTypes.Node));
        }
        return nodes;
    }
}
